package dataconvert

import (
	"encoding/binary"
	"math"
	"reflect"
)

func ConvertFromBytesLE[T int8 | uint8 | int16 | uint16 | int32 | uint32 | uint64 | int64 | float32 | float64](buffer []byte) ([]T, error) {
	var p T
	switch reflect.TypeOf(p).Kind() {
	case reflect.Int8:
		fallthrough
	case reflect.Uint8:
		ss := make([]T, len(buffer))
		for i, v := range buffer {
			ss[i] = T(v)
		}
		return ss, nil
	case reflect.Int16:
		fallthrough
	case reflect.Uint16:
		result := make([]T, len(buffer)/2)
		for i := 0; i < len(result); i++ {
			result[i] = T(binary.LittleEndian.Uint16(buffer[2*i : i*2+2]))
		}
		return result, nil
	case reflect.Int32:
		fallthrough
	case reflect.Uint32:
		result := make([]T, len(buffer)/4)
		for i := 0; i < len(result); i++ {
			result[i] = T(binary.LittleEndian.Uint32(buffer[4*i : i*4+4]))
		}
		return result, nil
	case reflect.Int64:
		fallthrough
	case reflect.Uint64:
		result := make([]T, len(buffer)/8)
		for i := 0; i < len(result); i++ {
			result[i] = T(binary.LittleEndian.Uint64(buffer[8*i : i*8+8]))
		}
		return result, nil
	case reflect.Float32:
		result := make([]T, len(buffer)/4)
		for i := 0; i < len(result); i++ {
			result[i] = T(math.Float32frombits(binary.LittleEndian.Uint32(buffer[4*i : i*4+4])))
		}
		return result, nil
	case reflect.Float64:
		result := make([]T, len(buffer)/8)
		for i := 0; i < len(result); i++ {
			result[i] = T(math.Float64frombits(binary.LittleEndian.Uint64(buffer[8*i : i*8+8])))
		}
		return result, nil
	default:
		return nil, nil
	}
}

func ConvertToBytesLE[T int8 | uint8 | int16 | uint16 | int32 | uint32 | uint64 | int64 | float32 | float64](buffer []T) ([]byte, error) {
	var p T
	switch reflect.TypeOf(p).Kind() {
	case reflect.Int8:
		fallthrough
	case reflect.Uint8:
		result := make([]byte, len(buffer))
		for i := 0; i < len(buffer); i++ {
			result[i] = byte(buffer[i])
		}
		return result, nil
	case reflect.Int16:
		fallthrough
	case reflect.Uint16:
		result := make([]byte, len(buffer)*2)
		for i := 0; i < len(buffer); i++ {
			binary.LittleEndian.PutUint16(result[i*2:i*2+2], uint16(buffer[i]))
		}
		return result, nil
	case reflect.Int32:
		fallthrough
	case reflect.Uint32:
		result := make([]byte, len(buffer)*4)
		for i := 0; i < len(buffer); i++ {
			binary.LittleEndian.PutUint32(result[i*4:i*4+4], uint32(buffer[i]))
		}
		return result, nil
	case reflect.Int64:
		fallthrough
	case reflect.Uint64:
		result := make([]byte, len(buffer)*8)
		for i := 0; i < len(buffer); i++ {
			binary.LittleEndian.PutUint64(result[i*8:i*8+8], uint64(buffer[i]))
		}
		return result, nil
	case reflect.Float32:
		result := make([]byte, len(buffer)*4)
		for i := 0; i < len(buffer); i++ {
			binary.LittleEndian.PutUint32(result[i*4:i*4+4], math.Float32bits(float32(buffer[i])))
		}
		return result, nil
	case reflect.Float64:
		result := make([]byte, len(buffer)*8)
		for i := 0; i < len(buffer); i++ {

			binary.LittleEndian.PutUint64(result[i*8:i*8+8], math.Float64bits(float64(buffer[i])))
		}
		return result, nil
	default:
		return nil, nil
	}
}

func ConvertFromBytesBE[T int32 | uint32 | uint64 | int64 | float32 | float64](buffer []byte) ([]T, error) {
	var p T
	switch reflect.TypeOf(p).Kind() {
	case reflect.Int32:
		fallthrough
	case reflect.Uint32:
		result := make([]T, len(buffer)/4)
		for i := 0; i < len(result); i++ {
			result[i] = T(binary.BigEndian.Uint32(buffer[4*i : i*4+4]))
		}
		return result, nil
	case reflect.Int64:
		fallthrough
	case reflect.Uint64:
		result := make([]T, len(buffer)/8)
		for i := 0; i < len(result); i++ {
			result[i] = T(binary.BigEndian.Uint64(buffer[8*i : i*8+8]))
		}
		return result, nil
	case reflect.Float32:
		result := make([]T, len(buffer)/4)
		for i := 0; i < len(result); i++ {
			result[i] = T(math.Float32frombits(binary.BigEndian.Uint32(buffer[4*i : i*4+4])))
		}
		return result, nil
	case reflect.Float64:
		result := make([]T, len(buffer)/8)
		for i := 0; i < len(result); i++ {
			result[i] = T(math.Float64frombits(binary.BigEndian.Uint64(buffer[8*i : i*8+8])))
		}
		return result, nil
	default:
		return nil, nil
	}
}

func ConvertToBytesBE[T int32 | uint32 | uint64 | int64 | float32 | float64](buffer []T) ([]byte, error) {
	var p T
	switch reflect.TypeOf(p).Kind() {
	case reflect.Int32:
		fallthrough
	case reflect.Uint32:
		result := make([]byte, len(buffer)*4)
		for i := 0; i < len(buffer); i++ {
			binary.BigEndian.PutUint32(result[i*4:i*4+4], uint32(buffer[i]))
		}
		return result, nil
	case reflect.Int64:
		fallthrough
	case reflect.Uint64:
		result := make([]byte, len(buffer)*8)
		for i := 0; i < len(buffer); i++ {
			binary.BigEndian.PutUint64(result[i*8:i*8+8], uint64(buffer[i]))
		}
		return result, nil
	case reflect.Float32:
		result := make([]byte, len(buffer)*4)
		for i := 0; i < len(buffer); i++ {
			binary.BigEndian.PutUint32(result[i*4:i*4+4], math.Float32bits(float32(buffer[i])))
		}
		return result, nil
	case reflect.Float64:
		result := make([]byte, len(buffer)*8)
		for i := 0; i < len(buffer); i++ {
			binary.BigEndian.PutUint64(result[i*8:i*8+8], math.Float64bits(float64(buffer[i])))
		}
		return result, nil
	default:
		return nil, nil
	}
}
